package com.dzm.aspect;

import com.dzm.anno.RequiresPermissions;
import com.dzm.constants.ClientConstant;
import com.dzm.constants.RedisConstant;
import com.dzm.constants.UserConstant;
import com.dzm.enums.Logical;
import com.dzm.except.NoPermissionException;
import com.dzm.to.LoginUser;
import com.dzm.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * 作者：Dzm
 * 时间：2024-08-26-14:04
 * 功能：
 */

@Component
@Aspect
public class PreAuthAspect {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     *
     * @param point 方法处理
     * @param permissions   当前方法所需权限
     * @return
     * @throws Throwable
     */
    @Around("@annotation(permissions)")
    public Object innerAround(ProceedingJoinPoint point, RequiresPermissions permissions) throws Throwable {
        //获取方法所需权限
        String[] methodPermissions = permissions.value();

        //获取当前用户的权限
        List<String> userPermissions = getUserPermission();

        //判断当前用户是否有权限
        isHavePermission(methodPermissions, userPermissions, permissions.logical());

        return point.proceed();
    }

    /**
     *
     * @param methodPermissions 方法所需权限
     * @param userPermissions   用户权限
     * @param logical   权限联合方式
     */
    private void isHavePermission(String[] methodPermissions, List<String> userPermissions, Logical logical) {
        for (String methodPermission : methodPermissions) {
            if(logical == Logical.AND) {
                //用户权限中少了一个权限就抛异常
                if(!userPermissions.contains(methodPermission)) {
                    throw new NoPermissionException("访问权限不足");
                }
            }else if(logical == Logical.OR) {
                //用户包含一个权限就结束
                if(userPermissions.contains(methodPermission)) return;
            }
        }

        //如果是或类型，没有一个权限被包含，抛异常
        if(logical == Logical.OR) {
            throw new NoPermissionException("访问权限不足");
        }
    }

    /**
     * 获取当前用户权限
     * @return
     */
    private List<String> getUserPermission() {
        //获取当前请求上下文属性
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(attributes != null) {
            //获取请求
            HttpServletRequest request = attributes.getRequest();

            String cliToken = request.getHeader(ClientConstant.CLIENT_TOKEN_NAME);
            String token = cliToken.replaceFirst(ClientConstant.CLIENT_TOKEN_PRE, "");

            //解析token
            Claims claims = JwtUtil.parseToken(token);
            String uuid = (String) claims.get(UserConstant.UUID_NAME);

            //根据uud获取用户
            LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(RedisConstant.LOGIN_TOKEN + uuid);
            if(loginUser != null) {
                List<String> permissions = loginUser.getPermissions();
                return permissions;
            }
        }

        return null;
    }

}
